﻿#include"XQHttpObject.h"
#include"XQHttpHeadRequest.h"
#include"XQHttpHeadReply.h"
#include"XQCoding.h"
#include"XQHttpReplyObject.h"
#include"XQAlgorithm.h"
#include"XQLog.hpp"
#include<QAbstractSocket>
#include<QHostAddress>
XQHttpObject::XQHttpObject(QObject* parent)
{
	init();
}

XQHttpObject::~XQHttpObject()
{
}

void XQHttpObject::defaultBuffFunc(QIODevice* socket, XQHttpHeadObject* head, const QByteArray& buffer)
{
	if (socket==nullptr||head == nullptr||buffer.isEmpty())
		return;
	head->addBuffer(buffer);
	if (head->isBuffAcceptFinish())
	{
		auto data = head->buffer();
		auto Encoding = QString(head->header("Content-Encoding"));
		if (Encoding.toLower() == QString("gzip").toLower())
		{//将数据gzip解压
			data = gzipUnCompress(data);
		}
		else if (Encoding.toLower() == QString("deflate").toLower())
		{//将数据deflate解压
			data = deflateUnCompress(data);
		}
		head->setContent(data);
	}
}

//QString XQHttpObject::logName() const
//{
//	if(m_log==nullptr)
//		return QString();
//	return m_log->key();
//}

QString XQHttpObject::hostPort(QAbstractSocket* socket)
{
	QHostAddress ipAddress = socket->peerAddress();
	QString ip = ipAddress.toString(); // 转换为字符串形式
	// 获取已连接主机的端口号
	quint16 port = socket->peerPort();
	return QString("%1:%2").arg(ip).arg(port);
}

NetworkType XQHttpObject::networkType() const
{
	return m_networkType;
}

bool XQHttpObject::isTcpNetwork() const
{
	return m_networkType==NetworkType::Tcp;
}

bool XQHttpObject::isLocalNetwork() const
{
	return m_networkType == NetworkType::Local;
}

//bool XQHttpObject::isDebugModel(Http::Debug model)
//{
//	return  m_debug& model;
//}
//
//void XQHttpObject::setLogName(const QString& name)
//{
//	if (m_log)
//		m_log->setKey(name);
//}
//
//void XQHttpObject::setDebugModel(int model)
//{
//	m_debug = model;
//}
//
//void XQHttpObject::setDebugModel(Http::Debug model, bool open)
//{
//	if (open)
//		m_debug |= model;
//	else
//		m_debug &= (~model);
//}

void XQHttpObject::sendSignals(const QString& host, const QVariantList& data)
{
}

void XQHttpObject::addSlotFunc(const QString& name, std::function<QVariantList(const QVariantList&)> slotFunc)
{
	m_slotFunc[name] = slotFunc;
}

void XQHttpObject::removeSlotFunc(const QString& name)
{
	m_slotFunc.remove(name);
}

void XQHttpObject::clearSlotFunc()
{
	m_slotFunc.clear();
}

void XQHttpObject::addReplyModel(XQHttpReplyObject* event)
{
	if (event == nullptr)
		return;
	QWriteLocker lock(&m_lock);
	m_response << event;
	connect(event, &QObject::destroyed, [=]
		{
			QWriteLocker lock(&m_lock);
			m_response.remove(event);
		});
}

void XQHttpObject::removeResponse(XQHttpReplyObject* event)
{
	QWriteLocker lock(&m_lock);
	if (event && m_response.contains(event) && event->parent() == this)
		event->deleteLater();
	m_response.remove(event);
}

void XQHttpObject::clearResponse()
{
	QWriteLocker lock(&m_lock);
	for (auto event : m_response)
	{
		if (event->parent() == this)
			event->deleteLater();
	}
	m_response.clear();
}

void XQHttpObject::setBuffFunc(std::function<void(QIODevice* socket, XQHttpHeadObject* head, const QByteArray& buffer)>&& Func)
{
	m_buffFunc = Func;
}

//void XQHttpObject::setBuffFunc(std::function<void(QIODevice* socket, XQHttpHeadObject* head)>&& Func)
//{
//	m_buffFunc = Func;
//}

void XQHttpObject::init()
{
	m_debug = Http::Debug::error;
	/*addSignals("1231",this,&XQHttpObject::test);*/
	//m_buffFunc = defaultBuffFunc;
}

bool XQHttpObject::ishandlingSignalsRequest(XQHttpHeadObject* header)
{
	return header->header(QNetworkRequest::ContentTypeHeader) == SignalsRequestHeader;
}

bool XQHttpObject::handlingSignalsRequest(XQHttpHeadObject* header, const QByteArray& data, XQHttpHeadReply* reply)
{
	if (!ishandlingSignalsRequest(header))
		return false;
	//XQHttpHeadReply ready;
	QVariantList  ret;
	auto name = header->header(SignalsRequestHeader);//拿到信号名字
	auto args = QJsonDocument::fromJson(data).toVariant().toList();
	emit signalsRequest(name, args);
	if (m_slotFunc.contains(name))//查找绑定的相同名字槽函数
	{
		ret = m_slotFunc[name](args);
	}
	if (!ret.isEmpty())
	{//返回数据
		reply->setHeader(QNetworkRequest::ContentTypeHeader, SignalsReplyHeader);
		reply->setHeader(SignalsReplyHeader, header->header(SignalsRequestHeader));
		reply->setContent(variantList_toJson(ret));
		return true;
	}
	return false;
}

bool XQHttpObject::isReadContentFinish(const XQHttpHeadObject& head, const QByteArray& data, qlonglong startIndex)
{
	if (!head.header().contains("Content-Length"))
		return true;
	auto len = head.headContentLength();
	auto curSize = data.size() - startIndex;
	if (curSize >= len)
		return true;
	return false;
}

QByteArray XQHttpObject::GbkToUtf8(const QByteArray& data)
{
	return XQCoding::GbkToUtf8(data);
}

qint64 XQHttpObject::sendData(QIODevice* socket, XQHttpHeadObject* reply, const QString& AcceptEncoding)
{
	if (socket == nullptr || reply == nullptr)
		return 0;
	qint64 fileSize = 1_MB;//超出建议用deflate
	qint64 sendLen = 0;
	//查看当前数据是QIODevice 还是QByteArray
	if (!reply->device())//QByteArray
	{
		bool Compress = false;
		//是否可以压缩
		if (AcceptEncoding.contains("gzip", Qt::CaseInsensitive))
		{
			reply->setHeader("Content-Encoding", "gzip");
			Compress = true;
		}
		if (AcceptEncoding.contains("deflate", Qt::CaseInsensitive))
		{
			if (!Compress || reply->content().size() > fileSize)//没有gzip或文件超出一定大小时
				reply->setHeader("Content-Encoding", "deflate");
		}
		//处理压缩数据
		QByteArray data= reply->content();//数据
		auto Encoding = QString(reply->header("Content-Encoding"));
		if (Encoding.toLower()==QString("gzip").toLower())
		{//将数据转gzip格式
			data = gzipCompress(data);//压缩后的数据
		}
		else if (Encoding.toLower() == QString("deflate").toLower())
		{//将数据转gzip格式
			data = deflateCompress(data);//压缩后的数据
		}
		reply->setHeadContentLength(data.size());
		auto header = reply->header_toByteArray();
		sendLen += socket->write(header);
		sendLen += socket->write("\r\n");
		sendLen += socket->write(data);
	}
	else//QIODevice
	{
		auto dev = reply->device();
		if (!dev->isOpen())
			dev->open(QIODevice::OpenModeFlag::ReadOnly); 
		reply->setHeadContentLength(dev->size());
		auto header = reply->header_toByteArray();
		sendLen += socket->write(header);
		sendLen += socket->write("\r\n");
		
		while (!dev->atEnd())
		{
			sendLen += socket->write(dev->read(1024));
		}
		if (reply->isDeviceAutoDelete())
		{
			reply->setContent(QByteArray());
		}
	}
	return sendLen;
}
